<?php
declare (strict_types = 1);

namespace app\srapi\controller;
use hg\apidoc\annotation as Apidoc;
use app\common\controller\SrapiController;
use think\facade\Db;

/**
 * @Apidoc\Title("code登录")
 * @Apidoc\Group("login")
 */
class Login extends SrapiController
{
    /**
     * @Apidoc\Title("openid")
     * @Apidoc\Method("POST")
     * @Apidoc\Tag("sr")
     * @Apidoc\Param("code", require=true, desc="wx.login.code")
     * @Apidoc\Returned("openid", type="string", desc="openid")
     */
    public function openid(){
        $data = $this->request->param();
        $this->validate($data,[
            'code' => 'require'
        ],[
            'code.require' => '缺少参数code!',
        ]);
        $appId     = sysconfig('wxapp','app_id');
        $appSecret = sysconfig('wxapp','app_secret');
        $response = file_get_contents("https://api.weixin.qq.com/sns/jscode2session?appid=$appId&secret=$appSecret&js_code={$data['code']}&grant_type=authorization_code");
        if ($response===false){
            $this->error('微信小程序登录失败！');
        }
        $response = json_decode($response, true);
        if (!empty($response['errcode'])) {
            $this->error('操作失败!',$response);
        }
        $this->success("ok", ['openid'=>$response['openid']]);
    }

    /**
     * @Apidoc\Title("手机号登录")
     * @Apidoc\Method("POST")
     * @Apidoc\Tag("sr")
     * @Apidoc\Param("code", require=true, desc="e.detail.code")
     * @Apidoc\Param("openid", desc="openid")
     * @Apidoc\Returned("token", type="string", desc="token")
     * @Apidoc\Returned("user_id", type="int", desc="用户id")
     */
    public function authorizeTel(){
        $data = $this->request->post();
        $this->validate($data,[
            'code' => 'require',
        ],[
            'code.require' => '缺少参数code!',
        ]);
        $access_token = $this->getAccessToken();
        $url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=".$access_token;
        $json = $this->http_request($url,json_encode(['code'=>$data['code']]));
        $res = json_decode($json, true);
        if(!empty($res['errcode'])){
            $this->error($res['errmsg']);
        }
        $tel = $res['phone_info']['purePhoneNumber'];
        $user = Db::name('user')->where('tel',$tel)->find();
        if(empty($user)){
            $user_id = Db::name('user')->insertGetId([
                'openid' => $data['openid'] ?? '',
                'tel' => $tel,
                'nickname' => '用户'.substr($tel, -4),
                'avatar' => '',
                'more' => '',
                'session_key' => '',
                'create_time' => time(),
                'update_time' => time(),
            ]);
            if(!$user_id){
                $this->error('注册失败');
            }
        }else{
            $user_id = $user['id'];
        }
        $token  = $this->generate_user_token($user_id, 'wxapp');
        $this->success("登录成功!", ['token' => $token, 'user_id'=>$user_id]);
    }

    /**
     * @Apidoc\Title("code")
     * @Apidoc\Method("POST")
     * @Apidoc\Tag("sr")
     * @Apidoc\Param("code", require=true, desc="code")
     * @Apidoc\Returned("token", type="string", desc="token")
     * @Apidoc\Returned("user_id", type="int", desc="用户id")
     * @Apidoc\Returned("openid", type="int", desc="openid")
     * @Apidoc\Returned("login_type", type="int", desc="登录方式1授权2手机号3账号")
     */
    public function code(){
        $data = $this->request->param();
        $this->validate($data,[
            'code' => 'require'
        ],[
            'code.require' => '缺少参数code!',
        ]);
        $appId     = sysconfig('wxapp','app_id');
        $appSecret = sysconfig('wxapp','app_secret');
        $response = file_get_contents("https://api.weixin.qq.com/sns/jscode2session?appid=$appId&secret=$appSecret&js_code={$data['code']}&grant_type=authorization_code");
        if ($response===false){
            $this->error('操作失败，微信小程序登录失败！');
        }

        $response = json_decode($response, true);

        if (!empty($response['errcode'])) {
            $this->error('操作失败!',$response);
        }
        $openid     = $response['openid'];
        $sessionKey = $response['session_key'];
        $user = Db::name("user")->where('openid', $openid)->find();
        if(empty($user)){
            $res = Db::name('user')->insertGetId([
                'openid' => $openid,
                'nickname' => '',
                'avatar' => '',
                'more' => '',
                'session_key' => $sessionKey,
                'create_time' => time(),
                'update_time' => 0,
            ]);
            $user_id = $res;
            $update_time = 0;
        }else{
            Db::name("user")
                ->where(['id'=>$user['id']])
                ->update([
                    'session_key' => $sessionKey
                ]);
            $user_id = $user['id'];
            $update_time = $user['update_time'];
        }
        $token  = $this->generate_user_token($user_id, 'wxapp');
        $this->success("登录成功!", ['token' => $token, 'user_id'=>$user_id, 'openid'=>$openid, 'update_time'=>$update_time, 'login_type'=>explode(',',sysconfig('wxapp','login_type'))]);
    }

    private function generate_user_token($userId, $deviceType): string
    {
        $userTokenQuery = Db::name("user_token")
            ->where('user_id', $userId)
            ->where('device_type', $deviceType);
        $findUserToken  = $userTokenQuery->find();
        $currentTime    = time();
        $expireTime     = $currentTime + 24 * 3600 * 180;
        $token          = dechex(time()).uniqid('_'.dechex($userId),false).uniqid('_', true);
        if (empty($findUserToken)) {
            Db::name("user_token")->insert([
                'token'       => $token,
                'user_id'     => $userId,
                'expire_time' => $expireTime,
                'create_time' => $currentTime,
                'device_type' => $deviceType
            ]);
        } else {
            if ($findUserToken['expire_time'] > time() && !empty($findUserToken['token'])) {
                $token = $findUserToken['token'];
            } else {
                Db::name("user_token")
                    ->where('user_id', $userId)
                    ->where('device_type', $deviceType)
                    ->update([
                        'token'       => $token,
                        'expire_time' => $expireTime,
                        'create_time' => $currentTime
                    ]);
            }
        }

        return $token;
    }
}
